package simpledb.execution;

import simpledb.common.DbException;
import simpledb.storage.Tuple;
import simpledb.storage.TupleDesc;
import simpledb.transaction.TransactionAbortedException;

import java.util.NoSuchElementException;

/**
 * Operator 是所有执行算子的抽象基类。
 * 它封装了 close、next 和 hasNext 等基础迭代方法，
 * 子类只需实现 open 和 fetchNext 方法即可。
 */
public abstract class Operator implements OpIterator {

    private static final long serialVersionUID = 1L;

    /**
     * 判断是否还有下一个元组。
     *
     * @return 如果有下一个元组则返回 true，否则返回 false
     * @throws DbException
     * @throws TransactionAbortedException
     */
    public boolean hasNext() throws DbException, TransactionAbortedException {
        if (!this.open)
            throw new IllegalStateException("Operator 尚未打开");

        if (next == null)
            next = fetchNext();
        return next != null;
    }

    /**
     * 获取下一个元组。
     *
     * @return 下一个元组
     * @throws DbException
     * @throws TransactionAbortedException
     * @throws NoSuchElementException 如果没有更多元组
     */
    public Tuple next() throws DbException, TransactionAbortedException, NoSuchElementException {
        if (next == null) {
            next = fetchNext();
            if (next == null)
                throw new NoSuchElementException();
        }

        Tuple result = next;
        next = null; // 清空缓存的下一个元组
        return result;
    }

    /**
     * 抽象方法：获取下一个元组。
     * 子类必须实现此方法以提供具体的元组读取逻辑。
     *
     * @return 返回下一个元组；如果没有更多元组则返回 null
     * @throws DbException
     * @throws TransactionAbortedException
     */
    protected abstract Tuple fetchNext() throws DbException, TransactionAbortedException;

    /**
     * 关闭该操作符，释放资源。
     * 若子类重写该方法，应调用 super.close() 以保持内部状态一致。
     */
    public void close() {
        next = null; // 清空缓存
        this.open = false;
    }

    // 缓存下一个即将返回的元组
    private Tuple   next                 = null;

    // 表示当前操作符是否已打开
    private boolean open                 = false;

    // 预估该操作符输出的元组数量（用于查询优化器）
    private int     estimatedCardinality = 0;

    /**
     * 打开该操作符，准备开始读取数据。
     */
    public void open() throws DbException, TransactionAbortedException {
        this.open = true;
    }

    /**
     * 获取该操作符的所有子节点。
     * 对于只有一个子节点的操作符，返回长度为 1 的数组；
     * 对于连接操作符（如 Join），两个子节点顺序无关但应保持一致性。
     *
     * @return 子操作符数组
     */
    public abstract OpIterator[] getChildren();

    /**
     * 设置该操作符的子节点。
     * 对于只有一个子节点的操作符，使用 children[0]；
     * 对于连接操作符，使用 children[0] 和 children[1]。
     *
     * @param children 要设置的子操作符数组
     */
    public abstract void setChildren(OpIterator[] children);

    /**
     * 获取该操作符输出元组的描述信息。
     *
     * @return 元组描述对象 TupleDesc
     */
    public abstract TupleDesc getTupleDesc();

    /**
     * 获取该操作符预计输出的元组数量。
     * 此方法仅在 lab7 中使用（用于查询优化）。
     *
     * @return 预估的元组数量
     */
    public int getEstimatedCardinality() {
        return this.estimatedCardinality;
    }

    /**
     * 设置该操作符预计输出的元组数量。
     * 此方法仅在 lab7 中使用（用于查询优化）。
     *
     * @param card 预估的元组数量
     */
    public void setEstimatedCardinality(int card) {
        this.estimatedCardinality = card;
    }
}
